/*!
 * 基于开源项目 mui.jsonview改装的mui.jsonview
 * 添加了一些mui应用时的兼容-将JQ操作改为原生
 * 源地址:https://github.com/yesmeck/mui-jsonview/tree/master/dist
 * mui JSONView.
 * Licensed under the MIT License.
 */
(function($, isMui) {
	var Collapser, JSONFormatter, JSONView, JSON_VALUE_TYPES;
	JSON_VALUE_TYPES = ['object', 'array', 'number', 'string', 'boolean', 'null'];
	JSONFormatter = (function() {
		function JSONFormatter(options) {
			if (options == null) {
				options = {};
			}
			this.options = options;
		}

		JSONFormatter.prototype.htmlEncode = function(html) {
			if (html !== null) {
				return html.toString().replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
			} else {
				return '';
			}
		};

		JSONFormatter.prototype.jsString = function(s) {
			s = JSON.stringify(s).slice(1, -1);
			return this.htmlEncode(s);
		};

		JSONFormatter.prototype.decorateWithSpan = function(value, className) {
			return "<span class=\"" + className + "\">" + (this.htmlEncode(value)) + "</span>";
		};

		JSONFormatter.prototype.valueToHTML = function(value, level) {
			var valueType;
			if (level == null) {
				level = 0;
			}
			valueType = Object.prototype.toString.call(value).match(/\s(.+)]/)[1].toLowerCase();
			if (this.options.strict && !$.inArray(valueType, JSON_VALUE_TYPES)) {
				throw new Error("" + valueType + " is not a valid JSON value type");
			}
			return this["" + valueType + "ToHTML"].call(this, value, level);
		};

		JSONFormatter.prototype.nullToHTML = function(value) {
			return this.decorateWithSpan('null', 'null');
		};

		JSONFormatter.prototype.undefinedToHTML = function() {
			return this.decorateWithSpan('undefined', 'undefined');
		};

		JSONFormatter.prototype.numberToHTML = function(value) {
			return this.decorateWithSpan(value, 'num');
		};

		JSONFormatter.prototype.stringToHTML = function(value) {
			var multilineClass, newLinePattern;
			if (/^(http|https|file):\/\/[^\s]+$/i.test(value)) {
				return "<a href=\"" + (this.htmlEncode(value)) + "\"><span class=\"q\">\"</span>" + (this.jsString(value)) + "<span class=\"q\">\"</span></a>";
			} else {
				multilineClass = '';
				value = this.jsString(value);
				if (this.options.nl2br) {
					newLinePattern = /([^>\\r\\n]?)(\\r\\n|\\n\\r|\\r|\\n)/g;
					if (newLinePattern.test(value)) {
						multilineClass = ' multiline';
						value = (value + '').replace(newLinePattern, '$1' + '<br />');
					}
				}
				return "<span class=\"string" + multilineClass + "\">\"" + value + "\"</span>";
			}
		};

		JSONFormatter.prototype.booleanToHTML = function(value) {
			return this.decorateWithSpan(value, 'bool');
		};

		JSONFormatter.prototype.arrayToHTML = function(array, level) {
			var collapsible, hasContents, index, numProps, output, value, _i, _len;
			if (level == null) {
				level = 0;
			}
			hasContents = false;
			output = '';
			numProps = array.length;
			for (index = _i = 0, _len = array.length; _i < _len; index = ++_i) {
				value = array[index];
				hasContents = true;
				output += '<li>' + this.valueToHTML(value, level + 1);
				if (numProps > 1) {
					output += ',';
				}
				output += '</li>';
				numProps--;
			}
			if (hasContents) {
				collapsible = level === 0 ? '' : ' collapsible';
				return "[<ul class=\"array level" + level + collapsible + "\">" + output + "</ul>]";
			} else {
				return '[ ]';
			}
		};

		JSONFormatter.prototype.objectToHTML = function(object, level) {
			var collapsible, hasContents, key, numProps, output, prop, value;
			if (level == null) {
				level = 0;
			}
			hasContents = false;
			output = '';
			numProps = 0;
			for (prop in object) {
				numProps++;
			}
			for (prop in object) {
				value = object[prop];
				hasContents = true;
				key = this.options.escape ? this.jsString(prop) : prop;
				output += "<li><a class=\"prop\" href=\"javascript:;\"><span class=\"q\">\"</span>" + key + "<span class=\"q\">\"</span></a>: " + (this.valueToHTML(value, level + 1));
				if (numProps > 1) {
					output += ',';
				}
				output += '</li>';
				numProps--;
			}
			if (hasContents) {
				collapsible = level === 0 ? '' : ' collapsible';
				return "{<ul class=\"obj level" + level + collapsible + "\">" + output + "</ul>}";
			} else {
				return '{ }';
			}
		};

		JSONFormatter.prototype.jsonToHTML = function(json) {
			return "<div class=\"jsonview\">" + (this.valueToHTML(json)) + "</div>";
		};

		return JSONFormatter;

	})();
	(typeof module !== "undefined" && module !== null) && (module.exports = JSONFormatter);
	Collapser = (function() {
		function Collapser() {}

		Collapser.bindEvent = function(item, options) {
			var collapser;
			item.firstChild.addEventListener('click', (function(_this) {
				return function(event) {
					return _this.toggle(event.target.parentNode.firstChild, options);
				};
			})(this));
			collapser = document.createElement('div');
			collapser.className = 'collapser';
			collapser.innerHTML = options.collapsed ? '+' : '-';
			collapser.addEventListener('click', (function(_this) {
				return function(event) {
					return _this.toggle(event.target, options);
				};
			})(this));
			item.insertBefore(collapser, item.firstChild);
			if (options.collapsed) {
				return this.collapse(collapser);
			}
		};

		Collapser.expand = function(collapser) {
			var ellipsis, target;
			target = this.collapseTarget(collapser);
			if (target.style.display === '') {
				return;
			}
			ellipsis = target.parentNode.getElementsByClassName('ellipsis')[0];
			target.parentNode.removeChild(ellipsis);
			target.style.display = '';
			return collapser.innerHTML = '-';
		};

		Collapser.collapse = function(collapser) {
			var ellipsis, target;
			target = this.collapseTarget(collapser);
			if (target.style.display === 'none') {
				return;
			}
			target.style.display = 'none';
			ellipsis = document.createElement('span');
			ellipsis.className = 'ellipsis';
			ellipsis.innerHTML = ' &hellip; ';
			target.parentNode.insertBefore(ellipsis, target);
			return collapser.innerHTML = '+';
		};

		Collapser.toggle = function(collapser, options) {
			var action, collapsers, target, _i, _len, _results;
			if (options == null) {
				options = {};
			}
			target = this.collapseTarget(collapser);
			action = target.style.display === 'none' ? 'expand' : 'collapse';
			if (options.recursive_collapser) {
				collapsers = collapser.parentNode.getElementsByClassName('collapser');
				_results = [];
				for (_i = 0, _len = collapsers.length; _i < _len; _i++) {
					collapser = collapsers[_i];
					_results.push(this[action](collapser));
				}
				return _results;
			} else {
				return this[action](collapser);
			}
		};

		Collapser.collapseTarget = function(collapser) {
			var target, targets;
			targets = collapser.parentNode.getElementsByClassName('collapsible');
			if (!targets.length) {
				return;
			}
			return target = targets[0];
		};

		return Collapser;

	})();
	JSONView = {
		collapse: function(el) {
			if (el.innerHTML === '-') {
				return Collapser.collapse(el);
			}
		},
		expand: function(el) {
			if (el.innerHTML === '+') {
				return Collapser.expand(el);
			}
		},
		toggle: function(el) {
			return Collapser.toggle(el);
		}
	};
	//添加进入mui的选择器fun列表中
	return $.fn.JSONView = function() {
		var args, defaultOptions, formatter, json, method, options, outputDoc;
		args = arguments;
		if (JSONView[args[0]] != null) {
			method = args[0];
			return this.each(function() {
				var $this, level;
				$this = $(this);
				//兼容mui中的原生dom
				var collapserArray = null;
				var queryStr = '';
				//找寻符合条件的兄弟
				var findSiblingBrothers = function(domArray, queryStr) {
					var outArray = null;
					for (var i = 0, len = domArray.length; i < len; i++) {
						var brothers = domArray[i].querySelector(queryStr).parentNode.children;
						if (brothers) {
							if(!outArray){
								outArray = [];
							}		
							//选择符合条件的兄弟
							for (var i = 0, len = brothers.length; i < len; i++) {
								if (brothers[i].classList.contains('collapser')) {
									outArray.push(brothers[i]);
								}
							}
						}
					}
					return outArray;
				};
				if (args[1] != null) {
					level = args[1];
					queryStr = ".jsonview .collapsible.level" + level;
					if (isMui) {
						collapserArray = findSiblingBrothers($this, queryStr);
					} else {
						collapserArray = $this.find(queryStr).siblings('.collapser');
					}
					$.each(collapserArray, function() {
						return JSONView[method](this);
					});
				} else {
					queryStr = '.jsonview > ul > li .collapsible';
					if (isMui) {
						collapserArray = findSiblingBrothers($this, queryStr);
					} else {
						collapserArray = $this.find(queryStr).siblings('.collapser');
					}
					$.each(collapserArray, function() {
						return JSONView[method](this);
					});
				}
			});
		} else {
			json = args[0];
			options = args[1] || {};
			defaultOptions = {
				collapsed: false,
				nl2br: false,
				recursive_collapser: false,
				escape: true,
				strict: false
			};
			options = $.extend(defaultOptions, options);
			formatter = new JSONFormatter(options);
			if (Object.prototype.toString.call(json) === '[object String]') {
				json = JSON.parse(json);
			}
			outputDoc = formatter.jsonToHTML(json);
			return this.each(function() {
				var $this, item, items, _i, _len, _results;
				$this = $(this);
				//这个注意,如果是mui需要兼容处理
				if (isMui) {
					for (var i = 0, len = $this.length; i < len; i++) {
						$this[i].innerHTML = outputDoc;
					}
				} else {
					$this.html(outputDoc);
				}
				items = $this[0].getElementsByClassName('collapsible');
				_results = [];
				for (_i = 0, _len = items.length; _i < _len; _i++) {
					item = items[_i];
					if (item.parentNode.nodeName === 'LI') {
						_results.push(Collapser.bindEvent(item.parentNode, options));
					} else {
						_results.push(void 0);
					}
				}
				return _results;
			});
		}
	};
})(mui, true);